/*
 * gpio-ss805x.h
 *
 * The gpio driver for SS805X.
 *
 * Copyright (C) 2024 Sinh Micro, Inc.
 * Subject to the GNU Public License, version 2.
 *
 * Author: lixiang<lixiang@sinhmicro.com>
 * 
 * Encoding format: GB2312
 * Version: v1.2.2
 * Date: 2024-11-05
 */

#ifndef __HAL_GPIO_SS805X_H__
#define __HAL_GPIO_SS805X_H__

#include "hal-config.h"
#include "types.h"

/*
 * In order to optimize the code size, we MUST realize
 * the most of GPIO's API using Macro, please realize these APIs as below:
 * 1. enable input mode(For P0, P10~P14)
 *    GPIO_P0_IM_EN(bitmask)
 *    GPIO_P1_0_4_IM_EN(bitmask)
 *    @param[in]  bitmask, a bitmask for the port's I/Os(0 ~ 7),
 *                         if ANY I/O's bit is euqal to 1,
 *                         it will be set to input mode.
 * 2. enable output mode(For P0, P10~P14)
 *    GPIO_P0_OM_EN(bitmask)
 *    GPIO_P1_0_4_OM_EN(bitmask)
 *    ...
 * 3. enable high-z mode(For P0, P10~P14)
 *    GPIO_P0_HZ_EN(bitmask)
 *    GPIO_P1_0_4_HZ_EN(bitmask)
 *    ...
 * 4. output high (For P0, P10~P14)
 *    GPIO_P0_OUTPUT_HIGH(bitmask)
 *    GPIO_P1_0_4_OUTPUT_HIGH(bitmask)
 *    ...
 * 5. output low (For P0, P10~P14)
 *    GPIO_P0_OUTPUT_LOW(bitmask)
 *    GPIO_P1_0_4_OUTPUT_LOW(bitmask)
 *    ...
 * 6. input value get (For P0, P10~P14)
 *    GPIO_P0_INPUT_VAL_GET()
 *    GPIO_P1_0_4_INPUT_VAL_GET()
 *    ...
 *    return an 8-bit value for the port's I/Os(0 ~ 7)
 * 7. enable pull-up mode(For P0, P10~P13, P14)
 *    GPIO_P0_PU_EN(bitmask)
 *    GPIO_P1_0_3_PU_EN(bitmask)
 *    GPIO_P14_PU_EN(bitmask)
 *    @param[in]  bitmask, a bitmask for the port's I/Os(0 ~ 7),
 *                         if ANY I/O's bit is euqal to 1,
 *                         it will be set to pull-up mode.
 * 8. enable pull-down mode(For P0, P10~P13, P14)
 *    GPIO_P0_PD_EN(bitmask)
 *    GPIO_P1_0_3_PD_EN(bitmask)
 *    GPIO_P14_PD_EN(bitmask)
 *    ...
 * 9. enable no-pull mode(For P0, P10~P13, P14)
 *    GPIO_P0_NP_EN(bitmask)
 *    GPIO_P1_0_3_NP_EN(bitmask)
 *    GPIO_P14_NP_EN(bitmask)
 *    ...
 * 10. GPIO drive current config(For P0, P10~P14)
 *     GPIO_PXX_DRV_SOURCE_SET(x)
 *     GPIO_PXX_DRV_SINK_SET(x)
 *     @param[in] x drive Register value, can be 0,1,2,3 etc.
 *    ...
 * 11. GPIO anglog function force enable/disable(For P02, P03, P11, P12)
 *     GPIO_ENABLE_ANALOG_FORCE_XX
 *     GPIO_DISABLE_ANALOG_FORCE_XX
 */

/* input mode enable */
#define GPIO_P0_IM_EN(bitmask)              do { P0IE |= (bitmask); P0OE &= ~(bitmask); } while (0)
#define GPIO_P1_0_4_IM_EN(bitmask)          do { P1IE |= ((bitmask) & 0x1F); P1OE &= ~((bitmask) & 0x1F); } while (0)          

/* output mode enable */
#define GPIO_P0_OM_EN(bitmask)              do { P0OE |= (bitmask); P0IE &= ~(bitmask); } while (0)
#define GPIO_P1_0_4_OM_EN(bitmask)          do { P1OE |= ((bitmask) & 0x1F); P1IE &= ~((bitmask) & 0x1F); } while (0)

/* high-z mode enable */
#define GPIO_P0_HZ_EN(bitmask)              do { P0OE &= ~(bitmask); P0IE &= ~(bitmask); } while (0)
#define GPIO_P1_0_4_HZ_EN(bitmask)          do { P1OE &= ~((bitmask) & 0x1F); P1IE &= ~((bitmask) & 0x1F); } while (0)

/* output high */
#define GPIO_P0_OUTPUT_HIGH(bitmask)        (P0ODAT |= (bitmask))
#define GPIO_P1_0_4_OUTPUT_HIGH(bitmask)    (P1ODAT |= ((bitmask) & 0x1F))

/* output low */
#define GPIO_P0_OUTPUT_LOW(bitmask)         (P0ODAT &= ~(bitmask))
#define GPIO_P1_0_4_OUTPUT_LOW(bitmask)     (P1ODAT &= ~((bitmask) & 0x1F))

/* input value get */
#define GPIO_P0_INPUT_VAL_GET()             (P0IDAT)
#define GPIO_P1_0_4_INPUT_VAL_GET()         (P1IDAT & 0x1F)

/* enable pull-up mode */
#define GPIO_P0_PU_EN(bitmask)              do { P0PU |= (bitmask); P0PD &= ~(bitmask); } while (0)
#define GPIO_P1_0_3_PU_EN(bitmask)          do { P1PU |= ((bitmask) & 0x0F); P1PD &= ~((bitmask) & 0x0F); } while (0)
#define GPIO_P14_PU_EN(bitmask)             do { P1PU |= ((bitmask) & 0x10); P1PD &= ~((bitmask) & 0x10); } while (0)
 
/* enable pull-down mode */
#define GPIO_P0_PD_EN(bitmask)              do { P0PD |= (bitmask); P0PU &= ~(bitmask); } while (0)
#define GPIO_P1_0_3_PD_EN(bitmask)          do { P1PD |= ((bitmask) & 0x0F); P1PU &= ~((bitmask) & 0x0F); } while (0)
#define GPIO_P14_PD_EN(bitmask)             do { P1PD |= ((bitmask) & 0x10); P1PU &= ~((bitmask) & 0x10); } while (0)

/* enable no-pull mode */
#define GPIO_P0_NP_EN(bitmask)              do { P0PD &= ~(bitmask); P0PU &= ~(bitmask); } while (0)
#define GPIO_P1_0_3_NP_EN(bitmask)          do { P1PD &= ~((bitmask) & 0x0F); P1PU &= ~((bitmask) & 0x0F); } while (0)
#define GPIO_P14_NP_EN(bitmask)             do { P1PD &= ~((bitmask) & 0x10); P1PU &= ~((bitmask) & 0x10); } while (0)

/* GPIO dirve current config */
#define GPIO_P00_DRV_SOURCE_SET(x)          do { P0DRV &= ~(1 << 0); P0DRV |= (x << 0); } while (0)
#define GPIO_P00_DRV_SINK_SET(x)            GPIO_P00_DRV_SOURCE_SET(x)
#define GPIO_P01_DRV_SOURCE_SET(x)          do { P0DRV &= ~(1 << 1); P0DRV |= (x << 1); } while (0)
#define GPIO_P01_DRV_SINK_SET(x)            GPIO_P01_DRV_SOURCE_SET(x)
#define GPIO_P02_DRV_SOURCE_SET(x)          do { P0DRV &= ~(1 << 2); P0DRV |= (x << 2); } while (0)
#define GPIO_P02_DRV_SINK_SET(x)            GPIO_P02_DRV_SOURCE_SET(x)
#define GPIO_P03_DRV_SOURCE_SET(x)          do { P0DRV &= ~(1 << 3); P0DRV |= (x << 3); } while (0)
#define GPIO_P03_DRV_SINK_SET(x)            GPIO_P03_DRV_SOURCE_SET(x)
#define GPIO_P04_DRV_SOURCE_SET(x)          do { P0DRV &= ~(1 << 4); P0DRV |= (x << 4); } while (0)
#define GPIO_P04_DRV_SINK_SET(x)            GPIO_P04_DRV_SOURCE_SET(x)
#define GPIO_P05_DRV_SOURCE_SET(x)          do { P0DRV &= ~(1 << 5); P0DRV |= (x << 5); } while (0)
#define GPIO_P05_DRV_SINK_SET(x)            GPIO_P05_DRV_SOURCE_SET(x)
#define GPIO_P06_DRV_SOURCE_SET(x)          do { P0DRV &= ~(1 << 6); P0DRV |= (x << 6); } while (0)
#define GPIO_P06_DRV_SINK_SET(x)            GPIO_P06_DRV_SOURCE_SET(x)
#define GPIO_P07_DRV_SOURCE_SET(x)          do { P0DRV &= ~(1 << 7); P0DRV |= (x << 7); } while (0)
#define GPIO_P07_DRV_SINK_SET(x)            GPIO_P07_DRV_SOURCE_SET(x)

#define GPIO_P10_DRV_SOURCE_SET(x)          do { P1DRV &= ~(3 << 0); P1DRV |= (x << 0); } while (0)
#define GPIO_P10_DRV_SINK_SET(x)            GPIO_P10_DRV_SOURCE_SET(x)
#define GPIO_P11_DRV_SOURCE_SET(x)          do { P1DRV &= ~(3 << 2); P1DRV |= (x << 2); } while (0)
#define GPIO_P11_DRV_SINK_SET(x)            GPIO_P11_DRV_SOURCE_SET(x)
#define GPIO_P12_DRV_SOURCE_SET(x)          do { P1DRV &= ~(3 << 4); P1DRV |= (x << 4); } while (0)
#define GPIO_P12_DRV_SINK_SET(x)            GPIO_P12_DRV_SOURCE_SET(x)
#define GPIO_P13_DRV_SOURCE_SET(x)          do { P1DRV &= ~(3 << 6); P1DRV |= (x << 6); } while (0)
#define GPIO_P13_DRV_SINK_SET(x)            GPIO_P13_DRV_SOURCE_SET(x)
#define GPIO_P14_DRV_SOURCE_SET(x)          do { MFP3 &= ~(3 << 2); MFP3 |= (x << 2); } while (0)
#define GPIO_P14_DRV_SINK_SET(x)            GPIO_P14_DRV_SOURCE_SET(x)

enum MFP_P00 {
    MFP_P00_P00 = 0,
    MFP_P00_PWM2,
    MFP_P00_SSDCK,
    MFP_P00_RESERVED,
    MFP_P00_TX,
    MFP_P00_RX
};
#define GPIO_MFP_P00(x)     do { MFP0 &= ~(0x03 << 0); MFP0 |= ((x & 0x03) << 0);        \
                                 MFP3 &= ~(0x03 << 5); MFP3 |= (((x & 0x0C) >> 2) << 5); \
                               } while(0) 

enum MFP_P01 {
    MFP_P01_P01 = 0,
    MFP_P01_PWM3,
};
#define GPIO_MFP_P01(x)     do { MFP0 &= ~(0x03 << 2); MFP0 |= (x << 2); } while(0) 

enum MFP_P02 {
    MFP_P02_P02 = 0,
    MFP_P02_PWM2,
    MFP_P02_RESERVED,
    MFP_P02_TS0
};
#define GPIO_MFP_P02(x)     do { MFP0 &= ~(0x03 << 4); MFP0 |= (x << 4); } while(0) 

enum MFP_P03 {
    MFP_P03_P03 = 0,
    MFP_P03_PWM3,
    MFP_P03_RESERVED,
    MFP_P03_TS1
};
#define GPIO_MFP_P03(x)     do { MFP0 &= ~(0x03 << 6); MFP0 |= (x << 6); } while(0) 

enum MFP_P04 {
    MFP_P04_P04 = 0,
    MFP_P04_PWM4,
};
#define GPIO_MFP_P04(x)     do { MFP1 &= ~(0x03 << 0); MFP1 |= (x << 0); } while(0) 

enum MFP_P05 {
    MFP_P05_P05 = 0,
    MFP_P05_PWM5,
};
#define GPIO_MFP_P05(x)     do { MFP1 &= ~(0x03 << 2); MFP1 |= (x << 2); } while(0) 

enum MFP_P06 {
    MFP_P06_P06 = 0,
    MFP_P06_PWM6,
};
#define GPIO_MFP_P06(x)     do { MFP1 &= ~(0x03 << 4); MFP1 |= ((x & 0x03) << 4); } while(0)

enum MFP_P07 {
    MFP_P07_P07 = 0,
    MFP_P07_PWM4,
};
#define GPIO_MFP_P07(x)     do { MFP1 &= ~(0x03 << 6); MFP1 |= ((x & 0x03) << 6); } while(0)

enum MFP_P10 {
    MFP_P10_P10 = 0,
    MFP_P10_PWM0,
    MFP_P10_RX,
    MFP_P10_TX,
    MFP_P10_PWM3,
    MFP_P10_RESERVED
};
#define GPIO_MFP_P10(x)     do { MFP2 &= ~(0x83 << 0); MFP2 |= ((x & 0x03) << 0) | (((x & 0x04) >> 2) << 7); } while(0) 

enum MFP_P11 {
    MFP_P11_P11 = 0,
    MFP_P11_PWM6,
    MFP_P11_RESERVED,
    MFP_P11_AN4
};
#define GPIO_MFP_P11(x)     do { MFP2 &= ~(0x03 << 2); MFP2 |= (x << 2); } while(0) 

enum MFP_P12 {
    MFP_P12_P12 = 0,
    MFP_P12_RESERVED,
    MFP_P12_PWM6,
    MFP_P12_ACMP0_AN5
};
#define GPIO_MFP_P12(x)     do { MFP2 &= ~(0x03 << 4); MFP2 |= (x << 4); } while(0) 

enum MFP_P13 {
    MFP_P13_P13 = 0,
    MFP_P13_PWM1,
};
#define GPIO_MFP_P13(x)     do { MFP2 &= ~(0x01 << 6); MFP2 |= (x << 6); } while(0) 

enum MFP_P14 {
    MFP_P14_P14 = 0,
    MFP_P14_PWM5,
    MFP_P14_RESERVED,
    MFP_P14_AN6
};
#define GPIO_MFP_P14(x)     do { MFP3 &= ~(0x03 << 0); MFP3 |= (x << 0); } while(0) 

#define GPIO_ENABLE_ANALOG_FORCE_P02()     (PEXTCON |= (1 << 0))
#define GPIO_ENABLE_ANALOG_FORCE_P03()     (PEXTCON |= (1 << 1))
#define GPIO_ENABLE_ANALOG_FORCE_P11()     (PEXTCON |= (1 << 6))
#define GPIO_ENABLE_ANALOG_FORCE_P12()     (PEXTCON |= (1 << 7))

#define GPIO_DISABLE_ANALOG_FORCE_P02()    (PEXTCON &= ~(1 << 0))
#define GPIO_DISABLE_ANALOG_FORCE_P03()    (PEXTCON &= ~(1 << 1))
#define GPIO_DISABLE_ANALOG_FORCE_P11()    (PEXTCON &= ~(1 << 6))
#define GPIO_DISABLE_ANALOG_FORCE_P12()    (PEXTCON &= ~(1 << 7))

#define GPIO_PUDET  (*(volatile unsigned char xdata*)(0xFECF))

#endif
